package myLearnjdk.jdk.net;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;

/**
 * 主要测试一些socket相关的参数
 * @author yangcheng  
 * @date 2020年8月11日  
 * @version V1.0
 */
public class TestSocket {
	public static void main(String[] args) throws UnknownHostException, IOException {
		
	}
	
	/**
	 * Socket客户端的相关设置
	 * @throws UnknownHostException
	 * @throws IOException
	 */
	public static void startClient() throws UnknownHostException, IOException{
		Socket sct = new Socket();
		/**
		 * 控制TCP报文发送时小数据包组合成更大的数据包之后才发送的机制
		 */
		sct.setTcpNoDelay(true);
		
		/**
		 * 设置当socket关闭时，如何处理尚未发送出去的数据，默认close()方法立即返回，
		 * 但是数据仍然会发送出去，
		 * 参数1置为true表示开启关闭时发送数据，close()方法会阻塞，阻塞时长为参数2指定的时长（单位为秒）
		 */
		if(sct.getSoLinger() == -1){
			//当获取值为-1时表示目前为禁用模式
			sct.setSoLinger(true, 10);
		}
		
		/**
		 * 设置从socket中read()时的超时时间，默认为0，即无限时长
		 */
		if(sct.getSoTimeout() == 0 ){
			sct.setSoTimeout(10000);
		}
		
		/**
		 * 设置发送和接收缓存
		 * 计算Socket最大带宽：缓存/网络延迟(单位秒) --网络延迟通过ping命令可得到
		 * 如设置发送缓存大小为17520字节，延迟时间为0.5秒，则带宽为35040字节/秒==273.75kb/s
		 */
		sct.setSendBufferSize(1024*1024);
		sct.setReceiveBufferSize(1024*1024);
		
		/**
		 * 当打开此选项时，空闲的socket客户端会主动检测服务端是否正常，如果不正常会持续11分钟发送
		 * 检测数据包，如果一直未收到响应，则主动关闭socket客户端，默认关闭状态
		 */
		sct.setKeepAlive(true);
		
		/**
		 * 开启接收紧急报文（1byte），java中不会特别区分紧急报文和普通报文，需要用户
		 * 自行判断，开启之后，客户端通过sct.sendUrgentData(data);可发送紧急报文（报文长度都是
		 * 一个字节，当值大于255时，只会发送低位字节）---一般不使用
		 */
		sct.setOOBInline(true);
		
		/**
		 * setReuseAddress(true),当socket关闭之后，其占用端口可能还未释放，同时也可能还有未接收完成的数据，
		 * 通过setReuseAddress设置，标识当前端口可以被另一个socket所绑定，同时可以接收到上一个socket的数据。	
		 * 
		 */
		sct.setReuseAddress(true);
		
		/**
		 * 如若希望setReuseAddress生效，则必须采用socket.connect()的方法连接到远程服务器
		 */
		sct.connect(new InetSocketAddress("127.0.0.1", 8080));
	} 
	
	public static void startServer() throws IOException{
		ServerSocket soc = new ServerSocket(8080);
		/**
		 * 指定accept()方法的等待连接的最大时长，超时之后会抛出SocketTimeoutException
		 * 默认值为0，即永不超时，一般不需要设置此参数 
		 */
		soc.setSoTimeout(1000);
		
		/**
		 * 设置SO_ReuseAddress,其设置的效果与socket客户端一样,设置为true时，
		 * 允许一个socket未完全释放时，其监听端口可以被新的socket监控。
		 */
		soc.setReuseAddress(true);
		
		/**
		 * 设置接收缓冲区大小
		 */
		soc.setReceiveBufferSize(1024*1024);
		
	}
	
}
